りおんクロニクル


SQLite × トランザクション完全版|安全なINSERT・UPDATE・DELETEの書き方【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

SQLiteは軽量で扱いやすい一方、トランザクションを正しく使わないとデータが中途半端な状態になりがちです。 特に複数行INSERT・複数テーブル更新・業務アプリの重要処理では、トランザクションは必須です。 この記事では、C#からSQLiteのトランザクションを扱う実務レベルのパターンをまとめます。

この記事でわかること
・SQLiteトランザクションの基本(BEGIN / COMMIT / ROLLBACK)
・C#(Microsoft.Data.Sqlite)での実装パターン
・複数INSERTを一括で高速に処理する方法
・エラー時に確実にロールバックする書き方
・Dapper / EF Core でのトランザクション
・業務アプリ向けベストプラクティス

1. SQLiteトランザクションの基本

SQLiteのトランザクションは、基本的に次の3つで構成されます。

SQLレベルの例

BEGIN TRANSACTION;

INSERT INTO Users (Name, Age) VALUES ('A', 20);
INSERT INTO Users (Name, Age) VALUES ('B', 30);

COMMIT;

途中でエラーが起きた場合は ROLLBACK; を実行します。

2. C#(Microsoft.Data.Sqlite)での基本パターン

単純なトランザクション例

using Microsoft.Data.Sqlite;

var cs = "Data Source=sample.db";

using var con = new SqliteConnection(cs);
con.Open();

using var tran = con.BeginTransaction();

try
{
    using (var cmd = new SqliteCommand("INSERT INTO Users (Name, Age) VALUES (@name, @age)", con, tran))
    {
        cmd.Parameters.AddWithValue("@name", "Taro");
        cmd.Parameters.AddWithValue("@age", 25);
        cmd.ExecuteNonQuery();
    }

    using (var cmd = new SqliteCommand("INSERT INTO Logs (Message) VALUES (@msg)", con, tran))
    {
        cmd.Parameters.AddWithValue("@msg", "User Taro created");
        cmd.ExecuteNonQuery();
    }

    tran.Commit();
}
catch
{
    tran.Rollback();
    throw;
}

ポイント

注意: トランザクションを使わずに複数INSERTすると、途中でエラーが出たときに「半分だけ入っている」状態になります。

3. 複数行INSERTを一括で高速に処理する

大量INSERTは、1件ずつトランザクションを張ると非常に遅くなります。 1つのトランザクションでまとめてINSERTするのが定番パターンです。

var users = new[]
{
    new { Name = "A", Age = 20 },
    new { Name = "B", Age = 25 },
    new { Name = "C", Age = 30 },
};

using var con = new SqliteConnection(cs);
con.Open();

using var tran = con.BeginTransaction();

try
{
    foreach (var u in users)
    {
        using var cmd = new SqliteCommand(
            "INSERT INTO Users (Name, Age) VALUES (@name, @age)", con, tran);

        cmd.Parameters.AddWithValue("@name", u.Name);
        cmd.Parameters.AddWithValue("@age", u.Age);
        cmd.ExecuteNonQuery();
    }

    tran.Commit();
}
catch
{
    tran.Rollback();
    throw;
}

メリット

4. 非同期(async/await)+トランザクション

UIフリーズを避けるため、非同期APIと組み合わせることも多いです。

using var con = new SqliteConnection(cs);
await con.OpenAsync();

using var tran = await con.BeginTransactionAsync();

try
{
    using (var cmd = new SqliteCommand(
        "INSERT INTO Users (Name, Age) VALUES (@name, @age)", con, tran))
    {
        cmd.Parameters.AddWithValue("@name", "AsyncUser");
        cmd.Parameters.AddWithValue("@age", 40);
        await cmd.ExecuteNonQueryAsync();
    }

    await tran.CommitAsync();
}
catch
{
    await tran.RollbackAsync();
    throw;
}

5. Dapperでのトランザクション

Dapperは Execute / Querytransaction パラメータを渡すだけです。

using Dapper;
using Microsoft.Data.Sqlite;

using var con = new SqliteConnection(cs);
con.Open();

using var tran = con.BeginTransaction();

try
{
    con.Execute(
        "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)",
        new { Name = "DapperA", Age = 20 },
        transaction: tran
    );

    con.Execute(
        "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)",
        new { Name = "DapperB", Age = 30 },
        transaction: tran
    );

    tran.Commit();
}
catch
{
    tran.Rollback();
    throw;
}

非同期版

await con.ExecuteAsync(
    "INSERT INTO Users (Name, Age) VALUES (@Name, @Age)",
    new { Name = "AsyncDapper", Age = 50 },
    transaction: tran
);

6. EF Coreでのトランザクション

EF Coreは Database.BeginTransaction() を使います。

using var db = new AppDbContext();

using var tran = await db.Database.BeginTransactionAsync();

try
{
    db.Users.Add(new User { Name = "EFUser1", Age = 20 });
    db.Users.Add(new User { Name = "EFUser2", Age = 30 });

    await db.SaveChangesAsync();

    await tran.CommitAsync();
}
catch
{
    await tran.RollbackAsync();
    throw;
}

ポイント

7. トランザクションとロック(database is locked)

SQLiteは同時書き込みに弱い トランザクション中に別スレッド・別プロセスから書き込みが来ると database is locked が発生しやすくなります。

対策

8. 業務アプリでのベストプラクティス

まとめ:SQLite × トランザクションは“壊れないデータ”の必須技術

SQLiteは軽量で導入しやすい一方、 トランザクション設計がそのまま信頼性に直結するDBです。 この記事をベースに、「速くて壊れない」更新処理を組み立ててみてください。

前のページ  次のページ